package com.jwgf.smarowindingmachine_unity.ui;

import android.Manifest;
import android.app.ActivityManager;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.view.Menu;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;

import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.fragment.app.FragmentActivity;

import com.jwgf.Half485.fxthreadpool.FxCommandFeeder;
import com.jwgf.Half485.fxthreadpool.FxCommandManager;
import com.jwgf.Half485.fxthreadpool.FxPLCData;
import com.jwgf.Half485.modbusthreadpool.ModbusCommandFeeder;
import com.jwgf.Half485.modbusthreadpool.ModbusCommandManager;
import com.jwgf.Half485.modbusthreadpool.PLCData;
import com.jwgf.canstate.CanHandShakeTest;
import com.jwgf.canstate.SmaroCanHandState;
import com.jwgf.canstate.SmaroCanState;
import com.jwgf.comlibrary.CANManager;
import com.jwgf.comlibrary.Half485Manager;
import com.jwgf.common.AppContext;
import com.jwgf.common.MD5;
import com.jwgf.common.ScreenOffTimeoutControl;
import com.jwgf.common.ViewCache;
import com.jwgf.fault.FaultContent;
import com.jwgf.fault.FaultRecorder;
import com.jwgf.fault.IXmlParse;
import com.jwgf.fault.PullFaultParse;
import com.jwgf.faultnavigation.FaultNavigationAttr;
import com.jwgf.faultnavigation.FaultNavigationDetailDialog;
import com.jwgf.faultnavigation.PictureDialog;
import com.jwgf.faultnavigation.PictureId;
import com.jwgf.fram.FramManager;
import com.jwgf.mqtt.MqttClientManager;
import com.jwgf.mqtt.VcroMqttListener;
import com.jwgf.mqtt.json.JsonBuilder;
import com.jwgf.objectbox.ObjectBox;
import com.jwgf.protocolstack.CommandFeeder;
import com.jwgf.protocolstack.ProtocolStack;
import com.jwgf.report.ShiftManager;
import com.jwgf.smarowindingmachine_unity.R;
import com.jwgf.smarowindingmachine_unity.logic.CanCommand;
import com.jwgf.smarowindingmachine_unity.logic.MachineParameterSharedPreference;
import com.jwgf.smarowindingmachine_unity.logic.Report;
import com.jwgf.smarowindingmachine_unity.logic.RxMerge2Event;
import com.jwgf.smarowindingmachine_unity.logic.ShiftChangeOperator;
import com.jwgf.smarowindingmachine_unity.logic.SmaroWindingMachineCanReadSucceedListener;
import com.jwgf.smarowindingmachine_unity.logic.SmaroWindingMachineModBusReadParser;
import com.jwgf.webserver.nanoserver.NanoHttpServer;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.TimeUnit;

import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.core.Observer;
import io.reactivex.rxjava3.disposables.Disposable;
import io.reactivex.rxjava3.functions.Consumer;
import io.reactivex.rxjava3.schedulers.Schedulers;


public class SmaroWindingMachineActivity extends FragmentActivity {
    private RxMerge2Event<String> merge = new RxMerge2Event();
    private Disposable disposable;
    private Consumer<Long> consumer;

    //Webserver
    private NanoHttpServer webServer;

    public static ProtocolStack canHandStack;
    public static ProtocolStack canStack;
    public static CommandFeeder feeder;
    public PLCData plcData = PLCData.getInstance();
    public FxPLCData fxPLCData = FxPLCData.getInstance();
    byte[] TestACK = {0x00, 0x01, 0x60, 0x02, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00};
    private MachineParameterSharedPreference sp = MachineParameterSharedPreference.getInstance();

    private SharedPreferences.OnSharedPreferenceChangeListener listener = new SharedPreferences.OnSharedPreferenceChangeListener() {
        @Override
        public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
            merge.onNext(key);
        }
    };

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (disposable != null && ev.getAction() == MotionEvent.ACTION_UP) {
            disposable.dispose();
            disposable = Observable
                    .timer(ScreenOffTimeoutControl.getTimeout(), TimeUnit.MILLISECONDS)
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(consumer);
        } else if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            View v = getCurrentFocus();
            if (isShouldHideKeyboard(v, ev)) {
                boolean res = hideKeyboard(v.getWindowToken());
//                if (res) {
//                    //隐藏了输入法，则不再分发事件
//                    return true;
//                }
            }
        }
        return super.dispatchTouchEvent(ev);
    }

    private boolean isShouldHideKeyboard(View v, MotionEvent event) {
        if ((v instanceof EditText)) {
            int[] l = {0, 0};
            v.getLocationInWindow(l);
            int left = l[0],
                    top = l[1],
                    bottom = top + v.getHeight(),
                    right = left + v.getWidth();
            if (event.getX() > left && event.getX() < right
                    && event.getY() > top && event.getY() < bottom) {
                // 点击EditText的事件，忽略它。
                return false;
            } else {
                return true;
            }
        }
        // 如果焦点不是EditText则忽略，这个发生在视图刚绘制完，第一个焦点不在EditText上，和用户用轨迹球选择其他的焦点
        return false;
    }

    /**
     * 获取InputMethodManager，隐藏软键盘
     *
     * @param token
     */
    private boolean hideKeyboard(IBinder token) {
        if (token != null) {
            InputMethodManager im = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
            return im.hideSoftInputFromWindow(token, InputMethodManager.HIDE_NOT_ALWAYS);
        }
        return false;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
//        AppContext.getInstance().getRefWatcher().watch(this);
        Intent md5Intent = getIntent();
        String md5 = md5Intent.getStringExtra("MD5");
        String calcMD5 = MD5.md5(getString(R.string.password_num) + MD5.readLine("//data//serial"));
        if (md5 == null || !md5.toLowerCase().equals(calcMD5.toLowerCase())) {
            if (!AppContext.isDebug) {
//                finish();
            }
        }
        if (!isTaskRoot()) {
            finish();
            return;
        }
        //
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        //全屏
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setContentView(R.layout.activity_smaro_winding_machine);
        ObjectBox.init();

        getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
        FramManager.create("2");
        initFaultStringSource();

        DisplayMetrics dm = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(dm);
        int densityDpi = dm.densityDpi;
        int width = dm.widthPixels;
        int height = dm.heightPixels;
        // 初始化485
        Half485Manager.getInstance().init(getApplicationContext());
        Half485Manager.getInstance().openCom1(19200, 8, 1, 0);
        // 初始化CAN
        CANManager.getInstance().init(getApplicationContext());
        CANManager.getInstance().openCom1(200000);
        if (AppContext.isReform) {
            ProgressDialog pd = new ProgressDialog(this);
            pd.setTitle("正在初始化");
            pd.setCanceledOnTouchOutside(false);
            pd.show();
            Observable.just(CanCommand.initAll())
                    .subscribeOn(Schedulers.io())
                    .doOnComplete(() -> {
                        canStack = new ProtocolStack();
                        canStack.setState(new SmaroCanState(canStack));
                        canStack.registerReadSucceedListener(SmaroWindingMachineCanReadSucceedListener.getInstance());
                        canHandStack = new ProtocolStack();
                        canHandStack.setState(new SmaroCanHandState(canHandStack));
                        canHandStack.registerReadSucceedListener(SmaroWindingMachineCanReadSucceedListener.getInstance());
                        pd.dismiss();
                        if (sp.getValue(MachineParameterSharedPreference.PLC_TYPE, "0").equals("0")) {
                            ModbusCommandManager.getInstance().start();
                            new ModbusCommandFeeder().start();
                        } else {
                            FxCommandManager.getInstance().start();
                            new FxCommandFeeder().start();
                        }


                        // 挂载换班
                        ShiftManager.getInstance().init(new ShiftChangeOperator());
                    })
                    .subscribe(bytes -> {
                        for (int i = 0; i < 3; ++i) {
                            for (byte[] cmd : bytes) {
                                int canId = (cmd[0] << 8) | (cmd[1] & 0xff);
                                byte[] sendData = new byte[8];
                                System.arraycopy(cmd, 2, sendData, 0, sendData.length);
                                CANManager.getInstance().write1(canId, sendData);
                                Thread.sleep(10);
                            }
                            if (i < 2) {
                                Thread.sleep(10 * 1000 * (i + 1));
                            }
                        }
                    });
        } else {
            canStack = new ProtocolStack();
            canStack.setState(new SmaroCanState(canStack));
            canStack.registerReadSucceedListener(SmaroWindingMachineCanReadSucceedListener.getInstance());
            canHandStack = new ProtocolStack();
            canHandStack.setState(new SmaroCanHandState(canHandStack));
            canHandStack.registerReadSucceedListener(SmaroWindingMachineCanReadSucceedListener.getInstance());
            canHandStack.getStackHandler().postDelayed(new Runnable() {

                @Override
                public void run() {
                    canHandStack.putPriorityCmd(CanCommand.initAll());

                }
            }, 5000);
            SmaroWindingMachineModBusReadParser.getInstance();
            if (sp.getValue(MachineParameterSharedPreference.PLC_TYPE, "0").equals("0")) {
                ModbusCommandManager.getInstance().start();
                // 挂载换班,先换班，后开始polling，防止当班整机统计记录到上一班
                ShiftManager.getInstance().init(new ShiftChangeOperator());
                Observable.just(1).observeOn(Schedulers.computation()).subscribe(new Consumer<Integer>() {
                    @Override
                    public void accept(Integer integer) throws Throwable {
                        new ModbusCommandFeeder().start();
                    }
                });
            } else {
                FxCommandManager.getInstance().start();
                // 挂载换班,先换班，后开始polling，防止当班整机统计记录到上一班
                ShiftManager.getInstance().init(new ShiftChangeOperator());
                Observable.just(1).observeOn(Schedulers.computation()).subscribe(new Consumer<Integer>() {
                    @Override
                    public void accept(Integer integer) throws Throwable {
                        new FxCommandFeeder().start();
                    }
                });
            }


        }


        if (AppContext.isDebug) {
            new CanHandShakeTest();
        }


//        MqttClientManager.getInstance().connect();
        MqttClientManager.getInstance().setMqttMessageListener(new VcroMqttListener());

        Consumer<String> paraConsumer = new Consumer<String>() {
            @Override
            public void accept(String s) throws Exception {
                String parameterString = JsonBuilder.buildMachineParameter(s).toString();
                MqttClientManager.getInstance().publishMessage("Machine", parameterString, 0);
                String groupString = JsonBuilder.buildGroupParameter().toString();
                MqttClientManager.getInstance().publishMessage("Group", groupString, 0);
            }
        };

        merge.getObservable().throttleFirst(1, TimeUnit.SECONDS).subscribe(paraConsumer);

        Observable.timer(10, TimeUnit.SECONDS).subscribe(new Consumer<Long>() {
            @Override
            public void accept(Long aLong) throws Exception {
                MachineParameterSharedPreference.getInstance().registerMachineParaChangeListener(listener);
            }
        });


        if (AppContext.isDebug) {
            Observable.interval(10, TimeUnit.SECONDS).subscribe(new Consumer<Long>() {
                private int[] db = new int[72];

                @Override
                public void accept(Long aLong) throws Exception {
                    for (int spindleId = 1; spindleId < 73; spindleId++) {
                        db[spindleId - 1] += (int) (9 * Math.random());
                        Report.getInstance().parse60Cmd(spindleId, db[spindleId - 1], 0);
                    }
                }
            });
        }

//        new DirectBroadcastReceiver();

        EventBus.getDefault().register(this);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            requestStoragePermission();
        }
    }

    String[] PERMISSIONS_REQUIRED = {Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.ACCESS_FINE_LOCATION};

    protected void requestStoragePermission() {
        if (!allPermissionsGranted()) {
            // 此时还没有权限！
            ActivityCompat.requestPermissions(this, PERMISSIONS_REQUIRED, 1);
        } else {
            // 有权限了，去做该做的事情吧！
        }
    }

    private boolean allPermissionsGranted() {
        for (String permission : PERMISSIONS_REQUIRED) {
            if (ActivityCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
                return false;
            }
        }
        return true;
    }


    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (grantResults.length > 0) {
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // 权限通过

            } else {
                // 权限拒绝
                if (!ActivityCompat.shouldShowRequestPermissionRationale(this, permissions[0])) {
                    // 禁止后不再询问了！
                } else {
                    // 用户此次选择了禁止权限
                }
            }

        }
        return;
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onFaultNavigation(FaultNavigationAttr attr) {
        FaultNavigationDetailDialog dialog = new FaultNavigationDetailDialog();
        Bundle args = new Bundle();
        args.putInt(FaultNavigationDetailDialog.KEY, attr.code);
        dialog.setArguments(args);
        dialog.show(getSupportFragmentManager(), "FaultNavigation");
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onPictureClick(PictureId pictureId) {
        PictureDialog dialog = new PictureDialog();
        Bundle args = new Bundle();
        args.putInt(PictureDialog.KEY, pictureId.id);
        dialog.setArguments(args);
        dialog.show(getSupportFragmentManager(), "PictureDialog");
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.smaro_winding_machine, menu);
        return true;
    }

    private void asyncCreateViews() {
        if (getSupportFragmentManager().getFragments().isEmpty()) {
            List<Integer> layoutIdList = new ArrayList<>();
            layoutIdList.add(R.layout.fragment_title);

            layoutIdList.add(R.layout.fragment_main_menu);
            layoutIdList.add(R.layout.fragment_machine_state_menu);
            layoutIdList.add(R.layout.fragment_parameter_setting_menu);
            layoutIdList.add(R.layout.fragment_production_management_menu);
            layoutIdList.add(R.layout.fragment_equipment_maintenance_menu);

            layoutIdList.add(R.layout.fragment_machine_state_running_state);
            layoutIdList.add(R.layout.fragment_machine_state_machine_log);
            layoutIdList.add(R.layout.fragment_machine_state_machine_statistic);
            layoutIdList.add(R.layout.fragment_machine_state_spindle_state);
            layoutIdList.add(R.layout.fragment_machine_state_spindle_statistic);
            layoutIdList.add(R.layout.fragment_machine_state_cbf_state);
            layoutIdList.add(R.layout.fragment_machine_state_cbf_log);
            layoutIdList.add(R.layout.fragment_machine_state_doffer_state);
            layoutIdList.add(R.layout.fragment_machine_state_doffer_log);
            layoutIdList.add(R.layout.fragment_machine_state_direct_current);
            layoutIdList.add(R.layout.recycler_view);

            layoutIdList.add(R.layout.fragment_parameter_setting_system_parameter);
            layoutIdList.add(R.layout.fragment_parameter_setting_machine_parameter);
            layoutIdList.add(R.layout.fragment_parameter_setting_in_segment_parameter);
            layoutIdList.add(R.layout.fragment_parameter_setting_group);
            layoutIdList.add(R.layout.fragment_parameter_setting_spindle_parameter);
            layoutIdList.add(R.layout.fragment_parameter_setting_cbf_parameter);
            layoutIdList.add(R.layout.fragment_parameter_setting_doffer_parameter);

            layoutIdList.add(R.layout.fragment_production_management_change_class_setting);
            layoutIdList.add(R.layout.fragment_production_management_shift_report);
            layoutIdList.add(R.layout.fragment_production_management_statistics_report);
            layoutIdList.add(R.layout.fragment_production_management_variety_management);

            layoutIdList.add(R.layout.fragment_equipment_maintenance_fuction);
            layoutIdList.add(R.layout.fragment_equipment_maintenance_spindle_upgrade);
            layoutIdList.add(R.layout.fragment_equipment_maintenance_authority_setting);
            layoutIdList.add(R.layout.fragment_equipment_maintenance_software_upgrade);
            layoutIdList.add(R.layout.fragment_equipment_maintenance_network_setting);
            layoutIdList.add(R.layout.fragment_equipment_maintenance_device_setting);
            ViewCache.getInstance().generateViews(this, layoutIdList).subscribe(new Observer() {
                @Override
                public void onSubscribe(@io.reactivex.rxjava3.annotations.NonNull Disposable d) {

                }

                @Override
                public void onNext(@io.reactivex.rxjava3.annotations.NonNull Object o) {

                }

                @Override
                public void onError(@io.reactivex.rxjava3.annotations.NonNull Throwable e) {

                }

                @Override
                public void onComplete() {
                    SwitchPageManager.getInstance().init(getSupportFragmentManager());

                }
            });
        }
    }

    @Override
    protected void onStart() {
        super.onStart();
        asyncCreateViews();
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (disposable == null) {
            //锁屏定时操作
            consumer = new Consumer<Long>() {
                @Override
                public void accept(Long aLong) throws Exception {
                    if (!isForeground(SmaroWindingMachineActivity.this, ProtectActivity.class.getSimpleName())) {
                        LoginFragment.loginOut();
                        SwitchPageManager.getInstance().switchShortcut(getSupportFragmentManager(), R.id.machine_state_button, R.id.running_state_button);
                        Intent i = new Intent();
                        i.setClass(SmaroWindingMachineActivity.this, ProtectActivity.class);
                        startActivity(i);
                    }
                }
            };
        } else {
            disposable.dispose();
        }
        disposable = Observable
                .timer(ScreenOffTimeoutControl.getTimeout(), TimeUnit.MILLISECONDS)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(consumer);

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        ObjectBox.get().close();
    }

    private void initFaultStringSource() {
        IXmlParse xmlParse = new PullFaultParse();
        AssetManager manager = AppContext.getInstance().getAssets();
        InputStream is1;
        try {
            String language = Locale.getDefault().getLanguage();
            if (language.equals("zh")) {
                is1 = manager.open("fault/fault_map_smaro.xml");
            } else {
                is1 = manager.open("fault-en/fault_map_smaro.xml");
            }

            HashMap<Integer, FaultContent> faultMap = xmlParse.getFaultMapByParseXml(is1);
            FaultRecorder.getInstance().setFaultMap(faultMap);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public static boolean isForeground(Context context, String className) {
        if (context == null || TextUtils.isEmpty(className))
            return false;
        ActivityManager am = (ActivityManager) context.getSystemService(ACTIVITY_SERVICE);
        List<ActivityManager.RunningTaskInfo> list = am.getRunningTasks(1);
        for (ActivityManager.RunningTaskInfo taskInfo : list) {
            if (taskInfo.topActivity.getShortClassName().contains(className)) { // 说明它已经启动了
                return true;
            }
        }
        return false;
    }


}
